package net.xo68.destiny.starter.worker.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import net.xo68.destiny.contract.api.NodeSensor;
import net.xo68.destiny.contract.api.WorkerApi;
import net.xo68.destiny.contract.common.SystemConstants;
import net.xo68.destiny.contract.domain.RespondResult;
import net.xo68.destiny.contract.domain.StringRespondResult;
import net.xo68.destiny.contract.domain.job.AbortParameter;
import net.xo68.destiny.contract.domain.job.TriggerParameter;
import net.xo68.destiny.contract.domain.logger.LoggerInfo;
import net.xo68.destiny.contract.domain.node.NodeRegistry;
import net.xo68.destiny.core.discovery.NodeDiscoveryClient;
import net.xo68.destiny.starter.common.sched.DestinyTimingWheelScheduler;
import net.xo68.destiny.starter.worker.handler.JobHandler;
import net.xo68.destiny.starter.worker.handler.JobHandlerFactory;
import net.xo68.destiny.starter.worker.logger.JobLoggerReader;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 工作节点接口控制器
 * @author wuxie
 * @version 2020-10-26
 */
@Slf4j
@Api(tags = "工作节点接口控制器")
@RequestMapping("/api")
@RestController
public class WorkerApiController implements WorkerApi, NodeSensor {

    @Autowired
    private DestinyTimingWheelScheduler destinyTimingWheelScheduler;
    @Autowired
    private JobHandlerFactory jobHandlerFactory;
    @Autowired
    private JobLoggerReader jobLoggerReader;
    @Autowired
    private NodeDiscoveryClient nodeDiscoveryClient;

    @Override
    @GetMapping("/discovery")
    @ApiOperation(value = "节点信息")
    public RespondResult<List<NodeRegistry>> discovery(@RequestParam(value = "workGroupName", defaultValue = SystemConstants.DEFAULT_WORK_GROUP) String workGroupName){
        //final List<NodeHeartbeat> list = nodeHeartbeatService.validList(schedulerManagerProperties.getHeartbeatPeriodSecond() * 3L);
        final List<NodeRegistry> nodeRegistryList=new ArrayList<>();
        Iterator<NodeRegistry> manageIter = nodeDiscoveryClient.getManageNodes().iterator();
        while (manageIter.hasNext()){
            NodeRegistry nodeRegistry=manageIter.next();
            nodeRegistryList.add(nodeRegistry);
        }
        Iterator<NodeRegistry> workIter=nodeDiscoveryClient.getWorkNodesByGroupName(workGroupName).iterator();
        while (workIter.hasNext()){
            NodeRegistry nodeRegistry=workIter.next();
            nodeRegistryList.add(nodeRegistry);
        }
        return RespondResult.ok(nodeRegistryList);
    }

    @PostMapping("/receive")
    @ApiOperation(value = "接收服务端下发的任务")
    @Override
    public StringRespondResult receive(@RequestBody TriggerParameter triggerParameter) {
        try{
            Set<String> handlers=jobHandlerFactory.getHandleNames();
            if(handlers==null || handlers.isEmpty() || StringUtils.isBlank(triggerParameter.getJobHandler()) || !handlers.contains(triggerParameter.getJobHandler())){
                log.error("{}","此节点无法执行这个任务");
                return StringRespondResult.fail("此节点无法执行这个任务");
            }
            destinyTimingWheelScheduler.newTimeout(triggerParameter,triggerParameter.getDelay(), TimeUnit.MILLISECONDS);
            return StringRespondResult.ok();
        }catch (Exception e){
            log.error(e.getMessage(),e);
            return StringRespondResult.fail(e.getMessage());
        }
    }

    @GetMapping("/readLogger")
    @ApiOperation(value = "读取任务实例执行日志")
    @Override
    public LoggerInfo readLogger(@RequestParam("instanceId") long instanceId,@RequestParam(value = "beginLine",defaultValue = "0") int beginLine) {
        return jobLoggerReader.readLogger(instanceId,beginLine);
    }

    @PostMapping("/abort")
    @ApiOperation(value = "终止或取消任务实例")
    @Override
    public StringRespondResult abort(@RequestBody AbortParameter abortParameter) {
        TriggerParameter tp=new TriggerParameter();
        tp.setInstanceId(abortParameter.getInstanceId());
        boolean cancel=destinyTimingWheelScheduler.cancelTimeout(destinyTimingWheelScheduler.getSequencer().sequence(tp));
        if(cancel){
            return StringRespondResult.ok("任务取消命令接收成功");
        }
        JobHandler jobHandler = jobHandlerFactory.getJobHandler(abortParameter.getJobHandler());
        boolean abort=jobHandler.abort(abortParameter);
        if(abort){
            return StringRespondResult.ok("任务强制终止成功");
        }
        return StringRespondResult.fail();
    }

    @GetMapping("/state")
    @ApiOperation(value = "worker节点状态")
    @Override
    public RespondResult<Set<String>> state() {
        return RespondResult
                .ok(jobHandlerFactory.getHandleNames());
    }
}
